<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>arguments list</title>
    <style>
        body {
            display: flex;
            justify-content: center;
            align-items: center;
            min-height: 100vh;
        }

        #results li.pass {
            flex: 0;
            color: green;
        }

        #results li.fail {
            flex: 0;
            color: red;
            text-decoration: line-through;
        }
    </style>
</head>
<body>

<ui id="results"></ui>

<script>
    //断言
    function assert(value, desc) {
        var li = document.createElement('li');
        li.className = value ? 'pass' : 'fail';
        li.appendChild(document.createTextNode(desc));
        document.getElementById('results').appendChild(li);
    }

    //min() and max() 数组通用
    function smallest(array) {
        return Math.min.apply(Math, array);
    }   //笔记:apply方法可以将传入的参数数组作为可变长度的参数进行接收,
        // smallest([1,2,3,4]) == Math.min(1,2,3,4)

    function largest(array) {
        return Math.max.apply(Math, array);
    }

    assert(smallest([0, 1, 2, 3]) === 0, 'Located the smallest value.');

    assert(largest([0, 1, 2, 3]) === 3, 'Located the largest value.');

    //遍历可变长度的参数列表
    function merge(root) {  //实现merge()函数
        for (var i = 1; i < arguments.length; i++) {
            for (var key in arguments[i]) {
                root[key] = arguments[i][key];
            }
        }
        return root;
    }

    var merged = merge(
        {name: 'Batou'},
        {city: 'Niihama'}
    );
    assert(merged.name == 'Batou', 'The original name is intact.');
    assert(merged.city == 'Niihama', 'And the city has been copied over.');

    //arguments列表切片
    //笔记:直接使用slice方法是不行的,arguments不是数组,所以通过call方法调用数组对象原型的slice方法
    function multiMax(multi) {
        return multi * Math.max.apply(Math, Array.prototype.slice.call(arguments, 1));
    }
    assert(multiMax(3, 1, 2, 3) === 9, '3*3=9 (First arg, by largest.)');

    //函数重载!!!!!!!!!!!---------重载:一组具有相同名字,不同参数列表的函数/方法
    function addMethod(object, name, fn) {
        var old = object[name];
        object[name] = function () {
            if (fn.length == arguments.length) return fn.apply(this, arguments);
            else if (typeof old == 'function') return old.apply(this, arguments);
        };
    }

    //测试用例1
    //    var ninja = {};
    //    addMethod(ninja,'whatever',function(){/*do something*/})
    //    addMethod(ninja,'whatever',function(a){/*do something else*/})
    //    addMethod(ninja,'whatever',function(a,b){/*yet something else*/})

    //测试用例2
    var ninjas = {
        values: ['Dean Edwards', 'Sam Stephenson', 'Alex Russell']
    };
    addMethod(ninjas, 'find', function () {
        return this.values;
    });
    addMethod(ninjas, 'find', function (name) {
        var ret = [];
        for (var i = 0; i < this.values.length; i++)
            if (this.values[i].indexOf(name) == 0)
                ret.push(this.values[i]);
        return ret;
    });
    addMethod(ninjas, 'find', function (first, last) {
        var ret = [];
        for (var i = 0; i < this.values.length; i++)
            if (this.values[i] == (first + ' ' + last))
                ret.push(this.values[i])
        return ret;
    });
    assert(ninjas.find().length == 3,'Found all ninjas.');
    assert(ninjas.find('Sam').length == 1,'Found ninjas by first name.');
    assert(ninjas.find('Dean','Edwards').length == 1,'Found ninjas by first name and last name.');
    assert(ninjas.find('Alex','Russell','Jr') == null,'Found nothing.')


</script>
</body>
</html>